//----------------------------------------------------------------------------------------
// @Project Includes
#include "includes.h"

//----------------------------------------------------------------------------------------
// @Local Macro Define in the module
#define T_V_SOC_TABLE_TEMP_NUM    			(9)
#define T_V_SOC_TABLE_V_SOC_NUM   	    (11)

//----------------------------------------------------------------------------------------
// @Local Type defines in the module

static const int8_t T_C_Table_Temp[TEMP_CA_TABLE_LEN] =
{-20, -10, 0, 10, 20, 25, 30, 40, 50, 60};

static const int8_t T_V_SOC_Table_Temp[9] =
{-20, -10, 0, 10, 20, 25, 35, 45, 55};


static const uint16_t T_V_SOC_Table_V_LFP[T_V_SOC_TABLE_TEMP_NUM][T_V_SOC_TABLE_V_SOC_NUM] =
{
    {3460, 3306, 3308, 3306, 3296, 3285, 3277, 3272, 3268, 3263, 3251},/*-20?*/

    {3487, 3318, 3319, 3318, 3301, 3283, 3280, 3276, 3270, 3242, 3204},/*-10?*/

    {3430, 3324, 3324, 3325, 3308, 3285, 3282, 3280, 3258, 3207, 2866},/*0?*/

    {3510, 3326, 3327, 3327, 3309, 3287, 3285, 3283, 3256, 3205, 2937},/*10?*/

    {3420, 3329, 3329, 3328, 3316, 3290, 3288, 3285, 3251, 3204, 2758},/*20?*/

    {3438, 3330, 3330, 3330, 3316, 3292, 3290, 3285, 3251, 3204, 2733},/*25?*/

    {3415, 3332, 3331, 3331, 3314, 3294, 3293, 3280, 3246, 3204, 2718},/*35?*/

    {3418, 3333, 3332, 3332, 3316, 3297, 3295, 3280, 3246, 3204, 2701},/*45?*/

    {3431, 3335, 3334, 3333, 3321, 3300, 3299, 3284, 3248, 3205, 2693},/*55?*/

};

static const uint16_t T_V_SOC_Table_V_NCM[T_V_SOC_TABLE_TEMP_NUM][T_V_SOC_TABLE_V_SOC_NUM] =
{
    {4153, 4063, 3940, 3866, 3800, 3741, 3690, 3650, 3617, 3587, 3582},/*-20?*/

    {4174, 4029, 3942, 3862, 3782, 3713, 3661, 3626, 3601, 3576, 3532},/*-10?*/

    {4179, 4058, 3958, 3870, 3785, 3706, 3656, 3624, 3599, 3570, 3495},/*0?*/

    {4178, 4055, 3951, 3858, 3776, 3694, 3644, 3616, 3592, 3555, 3463},/*10?*/

    {4183, 4049, 3933, 3830, 3746, 3665, 3627, 3600, 3562, 3459, 3437},/*20?*/

    {4189, 4059, 3945, 3842, 3757, 3673, 3632, 3605, 3570, 3468, 3382},/*30?*/

    {4191, 4060, 3943, 3837, 3750, 3663, 3627, 3600, 3545, 3453, 3168},/*40?*/

    {4191, 4060, 3943, 3837, 3750, 3665, 3630, 3603, 3542, 3454, 3238},/*50?*/

    {4192, 4063, 3944, 3836, 3745, 3661, 3627, 3583, 3515, 3441, 3301},/*60?*/

};

static const int32_t T_V_SOC_Table_SOC[T_V_SOC_TABLE_V_SOC_NUM] =
{1000000, 900000, 800000, 700000, 600000, 500000, 400000, 300000, 200000, 100000, 0};

//----------------------------------------------------------------------------------------
// @Global Variables define in the module
volatile stc_soc_t g_stcSoc;

//----------------------------------------------------------------------------------------
// @Prototypes of functions in the module
static int8_t app_soc_tempCalc(void);
static int32_t app_soc_coulombCalc(void);
static void app_soc_displayWeightCalc(void);
static void app_soc_weightInitCalc(void);

static int32_t app_soc_getCellSocFromOCV(int8_t Temp, uint16_t Voltage);
static bool_t app_soc_cellReadyCheck(void);
static bool_t app_soc_cellResetSoc(void);

static bool_t app_soc_setInitalValue(void);
static uint32_t app_soc_getMaxCapFromTemp(int8_t Temp);

static void app_soc_arithmeticEnable(bool_t enable);
static void app_soc_setPackState(en_soc_packstate_t State);
static void app_soc_arithmetic(void);
static void app_soc_capInit(void);

//----------------------------------------------------------------------------------------
/**
 * @brief  soc temp calc
 * @param   none
 * @return  temp
 * @note   Note
 */
static int8_t app_soc_tempCalc(void)
{
    return ((int8_t)g_stcVar.i8tempAvg);
}

/**
 * @brief  soc coulomb calc
 * @param   none
 * @return  none
 * @note   Note
 */
static int32_t app_soc_coulombCalc(void)
{
    int32_t coulomb;
    coulomb = app_afe_getCoulomb();
    coulomb = coulomb/g_stcParm.stcConfig.u8cellP;
    return coulomb;
}

/**
 * @brief  soc sisplay weight calc
 * @param   none
 * @return  none
 * @note   Note
 */
static void app_soc_displayWeightCalc(void)
{
    if(g_stcParm.stcSoc.u32minLimitSOC >= g_stcSoc.stcdata.u32trueValue)
    {
        g_stcSoc.SOC_Deal = 0;
    }
    else if(g_stcParm.stcSoc.u32maxLimitSOC <= g_stcSoc.stcdata.u32trueValue)
    {
        g_stcSoc.SOC_Deal = SOC_COEFFICIENT;
    }
    else
    {
        g_stcSoc.SOC_Deal = (uint32_t)(((float_t)SOC_COEFFICIENT/
            (g_stcParm.stcSoc.u32maxLimitSOC - g_stcParm.stcSoc.u32minLimitSOC))*(g_stcSoc.stcdata.u32trueValue - g_stcParm.stcSoc.u32minLimitSOC));
        if(g_stcSoc.SOC_Deal > SOC_COEFFICIENT)
        {
            g_stcSoc.SOC_Deal = SOC_COEFFICIENT;
        }
    }

    if(g_stcSoc.enSocPackState == SOC_PACK_CHARGE_STATE)
    {
        if((g_stcSoc.SOC_Deal == SOC_COEFFICIENT) &&
            (g_stcSoc.stcdata.u32trueValue >= g_stcParm.stcSoc.u32maxLimitSOC))
        {
            g_stcSoc.W_Display = 1;
        }
        else
        {
            g_stcSoc.W_Display = (float_t)(SOC_COEFFICIENT - g_stcSoc.stcdata.u32displayValue)/
                (float_t)(SOC_COEFFICIENT - g_stcSoc.SOC_Deal);
        }
    }
    else
    {
        if((0 == g_stcSoc.stcdata.u32displayValue) &&
            (g_stcSoc.stcdata.u32trueValue <= g_stcParm.stcSoc.u32minLimitSOC))
        {
            g_stcSoc.W_Display = 0;
        }
        else
        {
           g_stcSoc.W_Display = (float_t)g_stcSoc.stcdata.u32displayValue/(float_t)g_stcSoc.SOC_Deal;
        }
    }
}

/**
 * @brief  soc weight init calc
 * @param   none
 * @return  none
 * @note   Note
 */
static void app_soc_weightInitCalc(void)
{
    g_stcSoc.W1 = (float_t)(g_stcSoc.i32socMax + g_stcSoc.i32socMin)/(float_t)(2*SOC_COEFFICIENT);
    g_stcSoc.W2 = (float_t)(1 - g_stcSoc.W1);
    g_stcSoc.b = 0;
}

/**
 * @brief  soc cell from ocv
 * @param   temp:temperature
 * @param   voltage:voltage
 * @return  none
 * @note   Note
 */
static int32_t app_soc_getCellSocFromOCV(int8_t Temp, uint16_t Voltage)
{
    uint8_t i, k, j = 0;
    uint16_t VoltageTable[T_V_SOC_TABLE_V_SOC_NUM];
    float_t TempSlope;
    int32_t Soc = 0;

    if(Temp <= T_V_SOC_Table_Temp[0])
    {
        for(k = 0; k < T_V_SOC_TABLE_V_SOC_NUM; k++)
        {
            if (g_stcParm.stcConfig.u8batteryType == TERNARY_MATERIAL_BATTERY_TYPE)
						{
								VoltageTable[k] = T_V_SOC_Table_V_NCM[0][k];
						}
						else
						{
								VoltageTable[k] = T_V_SOC_Table_V_LFP[0][k];
						}
        }
    }
    if(Temp >= T_V_SOC_Table_Temp[T_V_SOC_TABLE_TEMP_NUM - 1])
    {
        for(k = 0; k < T_V_SOC_TABLE_V_SOC_NUM; k++)
        {
						if (g_stcParm.stcConfig.u8batteryType == TERNARY_MATERIAL_BATTERY_TYPE)
						{
								VoltageTable[k] = T_V_SOC_Table_V_NCM[T_V_SOC_TABLE_TEMP_NUM - 1][k];
						}
						else
						{
								VoltageTable[k] = T_V_SOC_Table_V_LFP[T_V_SOC_TABLE_TEMP_NUM - 1][k];
						}
        }
    }

    uint8_t MediantIndex = (T_V_SOC_TABLE_TEMP_NUM - 1)/2;
    if(Temp < T_V_SOC_Table_Temp[MediantIndex])
    {
        j = MediantIndex - 1;
        for(i = 0; i < MediantIndex; i++, j--)
        {
            if(Temp >= T_V_SOC_Table_Temp[j])
            {
									TempSlope = (float_t)(Temp - T_V_SOC_Table_Temp[j])/
											(T_V_SOC_Table_Temp[j + 1] - T_V_SOC_Table_Temp[j]);
									for(k = 0; k < T_V_SOC_TABLE_V_SOC_NUM; k++)
									{
											if (g_stcParm.stcConfig.u8batteryType == TERNARY_MATERIAL_BATTERY_TYPE)
											{
													VoltageTable[k] = TempSlope*(T_V_SOC_Table_V_NCM[j + 1][k] - T_V_SOC_Table_V_NCM[j][k]) + T_V_SOC_Table_V_NCM[j][k];
											}
											else
											{
													VoltageTable[k] = TempSlope*(T_V_SOC_Table_V_LFP[j + 1][k] - T_V_SOC_Table_V_LFP[j][k]) + T_V_SOC_Table_V_LFP[j][k];
											}
									}
									break;
							}
				}
    }
    else if(Temp > T_V_SOC_Table_Temp[MediantIndex])
    {
        for(i = MediantIndex + 1; i < T_V_SOC_TABLE_TEMP_NUM; i++)
        {
            if(Temp <= T_V_SOC_Table_Temp[i])
            {
                TempSlope = (float_t)(Temp - T_V_SOC_Table_Temp[i - 1])/
                    (T_V_SOC_Table_Temp[i] - T_V_SOC_Table_Temp[i - 1]);
                for(k = 0; k < T_V_SOC_TABLE_V_SOC_NUM; k++)
                {
										if (g_stcParm.stcConfig.u8batteryType == TERNARY_MATERIAL_BATTERY_TYPE)
										{
											VoltageTable[k] = TempSlope*(T_V_SOC_Table_V_NCM[i][k] - T_V_SOC_Table_V_NCM[i - 1][k]) + T_V_SOC_Table_V_NCM[i -1][k];
										}
										else
										{
											VoltageTable[k] = TempSlope*(T_V_SOC_Table_V_LFP[i][k] - T_V_SOC_Table_V_LFP[i - 1][k]) + T_V_SOC_Table_V_LFP[i -1][k];
										}					
                }
                break;
            }
        }
    }
    else/* Temp == T_V_SOC_Table_Temp[MediantIndex] */
    {
        for(k = 0; k < T_V_SOC_TABLE_V_SOC_NUM; k++)
        {
						if (g_stcParm.stcConfig.u8batteryType == TERNARY_MATERIAL_BATTERY_TYPE)
						{
							VoltageTable[k] = T_V_SOC_Table_V_NCM[MediantIndex][k];
						}
						else
						{
							VoltageTable[k] = T_V_SOC_Table_V_LFP[MediantIndex][k];
						}			
        }
    }


    if(Voltage >= VoltageTable[0])
    {
        return Soc = SOC_COEFFICIENT;
    }
    if(Voltage <= VoltageTable[T_V_SOC_TABLE_V_SOC_NUM - 1])
    {
        return Soc = 0;
    }

    MediantIndex = (T_V_SOC_TABLE_V_SOC_NUM - 1)/2;
    i = 0; j = 0;  
    if(Voltage > VoltageTable[MediantIndex])
    {
        j = MediantIndex - 1;
        for(i = 0; i < MediantIndex; i++, j--)
        {
            if(Voltage <= VoltageTable[j])
            {
                Soc = ((float_t)(Voltage - VoltageTable[j + 1])/(VoltageTable[j] - VoltageTable[j + 1]))*
                    (T_V_SOC_Table_SOC[j] - T_V_SOC_Table_SOC[j + 1]) + T_V_SOC_Table_SOC[j + 1];
                break;
            }
        }
    }
    else if(Voltage < VoltageTable[MediantIndex])
    {
        for(i = MediantIndex; i < T_V_SOC_TABLE_V_SOC_NUM; i++)
        {
            if(Voltage >= VoltageTable[i])
            {
                Soc = ((float_t)(Voltage - VoltageTable[i])/(VoltageTable[i - 1] - VoltageTable[i]))*
                    (T_V_SOC_Table_SOC[i - 1] - T_V_SOC_Table_SOC[i]) + T_V_SOC_Table_SOC[i];
                break;
            }
        }
    }
    else
    {
        Soc = T_V_SOC_Table_SOC[MediantIndex];
    }

    return Soc;
}

/**
 * @brief  soc cell ready check
 * @param   none
 * @return  none
 * @note   Note
 */
static bool_t app_soc_cellReadyCheck(void)
{
	  if(g_stcVar.u16voltMax - g_stcVar.u16voltMin >= 500)
		{
				return false;
		}
		if ((g_stcVar.bvoltValidFlg == true)&&(g_stcVar.btmprValidFlg == true))
		{
				return true;
		}
		else
		{
				return false;
		}
}

/**
 * @brief  soc cell reset
 * @param   none
 * @return  none
 * @note   Note
 */
static bool_t app_soc_cellResetSoc(void)
{
    int8_t Temp;
	  uint8_t u8i;
	
    static uint8_t s_u8Calibration_times = 0;

    if (g_stcVar.u32totalSumVolt ==0)
    {
        return false;
    }

    s_u8Calibration_times++;
    
    if(s_u8Calibration_times < 30 && app_soc_cellReadyCheck() == false)
    {
        return false;
    }
    s_u8Calibration_times = 0;

    Temp = app_soc_tempCalc();
		
		for (u8i = 0; u8i < g_stcParm.stcConfig.u8cellS; u8i++)
		{
				g_stcSoc.stcdata.i32cellValue[u8i] = app_soc_getCellSocFromOCV(Temp, g_stcVar.u16cellVolt[u8i]);
		}

    g_stcSoc.stcdata.u8maxChnNum = g_stcVar.u8voltMaxNum - 1;
    g_stcSoc.stcdata.u8minChnNum = g_stcVar.u8voltMinNum - 1;
    g_stcSoc.i32socMax = g_stcSoc.stcdata.i32cellValue[g_stcVar.u8voltMaxNum - 1];
    g_stcSoc.i32socMin = g_stcSoc.stcdata.i32cellValue[g_stcVar.u8voltMinNum - 1];

    app_soc_weightInitCalc();

    g_stcSoc.stcdata.u32trueValue = g_stcSoc.W1*g_stcSoc.i32socMax + g_stcSoc.W2*g_stcSoc.i32socMin + g_stcSoc.b;

    SYSTEM_DEBUG("SOC:<< W1=  %f  ,   W2=  %f   MAX_VOLTAGE=  %d SOC_Max=  %d MIN_VOLTAGE=  %d SOC_Min=  %d b=  %d\r\n",g_stcSoc.W1,g_stcSoc.W2,g_stcVar.u16voltMax,g_stcSoc.i32socMax ,g_stcVar.u16voltMin,g_stcSoc.i32socMin,g_stcSoc.b);

    if(g_stcSoc.stcdata.u32trueValue >= SOC_COEFFICIENT)
    {
        g_stcSoc.stcdata.u32trueValue = SOC_COEFFICIENT;
        g_stcSoc.stcdata.u32displayValue = SOC_COEFFICIENT;
    }

    if(g_stcSoc.bdemarcate == true)
    {
        app_soc_displayWeightCalc();
        g_stcSoc.bdemarcate = false;
    }

    SOC_DEBUG("SOC:<< ACTION: cell SOC Srart calibration\r\n");
    return true;
}

/**
 * @brief  soc set soc init all value
 * @param   none
 * @return  none
 * @note   Note
 */
static bool_t app_soc_setInitalValue(void)
{
    if(app_soc_cellResetSoc() == false)
    {
        return false;
    }

    if(g_stcParm.stcSoc.u32minLimitSOC >= g_stcSoc.stcdata.u32trueValue)
    {
        g_stcSoc.SOC_Deal = 0;
    }
    else if(g_stcParm.stcSoc.u32maxLimitSOC <= g_stcSoc.stcdata.u32trueValue)
    {
        g_stcSoc.SOC_Deal = SOC_COEFFICIENT;
    }
    else
    {
        g_stcSoc.SOC_Deal = (uint32_t)(((float_t)SOC_COEFFICIENT/
            (g_stcParm.stcSoc.u32maxLimitSOC - g_stcParm.stcSoc.u32minLimitSOC))*(g_stcSoc.stcdata.u32trueValue - g_stcParm.stcSoc.u32minLimitSOC));
    }
    if(g_stcSoc.SOC_Deal >= SOC_COEFFICIENT)
    {
        g_stcSoc.SOC_Deal = SOC_COEFFICIENT;
    }

    g_stcSoc.W_Display = 1;

    if(SOC_PACK_CHARGE_STATE == g_stcSoc.enSocPackState)
    {
        g_stcSoc.stcdata.u32displayValue = g_stcSoc.W_Display*g_stcSoc.SOC_Deal +
            (float_t)(1 - g_stcSoc.W_Display)*(float_t)SOC_COEFFICIENT;
    }
    else
    {
        g_stcSoc.stcdata.u32displayValue = g_stcSoc.W_Display*g_stcSoc.SOC_Deal;
    }
    if(g_stcSoc.stcdata.u32displayValue > SOC_COEFFICIENT) 
    {
        g_stcSoc.stcdata.u32displayValue = SOC_COEFFICIENT;
    }

    return true;
}

/**
 * @brief  soc get max cap from temp
 * @param   Temp :temperture
 * @return  none
 * @note   Note
 */
static uint32_t app_soc_getMaxCapFromTemp(int8_t Temp)
{
    uint8_t i, j = 0;
    uint32_t MaxCap = g_stcSoc.u32tempCaTableMaxCap[0]; 

    if(Temp <= T_C_Table_Temp[0])
    {
        return MaxCap = g_stcSoc.u32tempCaTableMaxCap[0];
    }
    if(Temp >= T_C_Table_Temp[TEMP_CA_TABLE_LEN - 1])
    {
        return MaxCap = g_stcSoc.u32tempCaTableMaxCap[TEMP_CA_TABLE_LEN - 1];
    }

    uint8_t MediantIndex = (TEMP_CA_TABLE_LEN - 1)/2;
    if(Temp < T_C_Table_Temp[MediantIndex])
    {
        j = MediantIndex - 1;
        for(i = 0; i < MediantIndex; i++, j--)
        {
            if(Temp > T_C_Table_Temp[j])
            {
                MaxCap = ((float_t)(Temp - T_C_Table_Temp[j])/(T_C_Table_Temp[j + 1] - T_C_Table_Temp[j]))*
                    (g_stcSoc.u32tempCaTableMaxCap[j + 1] - g_stcSoc.u32tempCaTableMaxCap[j]) + g_stcSoc.u32tempCaTableMaxCap[j];
                break;
            }
        }
    }
    else if(Temp > T_C_Table_Temp[MediantIndex])
    {
        for(i = MediantIndex + 1; i < TEMP_CA_TABLE_LEN; i++)
        {
            if(Temp < T_C_Table_Temp[i])
            {
                MaxCap = ((float_t)(Temp - T_C_Table_Temp[i - 1])/(T_C_Table_Temp[i] - T_C_Table_Temp[i - 1]))*
                    (abs(g_stcSoc.u32tempCaTableMaxCap[i] - g_stcSoc.u32tempCaTableMaxCap[i - 1]))+ g_stcSoc.u32tempCaTableMaxCap[i -1];
                break;
            }
        }
    }
    else      /* Temp == T_C_Table_Temp[MediantIndex] */
    {
        MaxCap = g_stcSoc.u32tempCaTableMaxCap[MediantIndex];  
    }

    return MaxCap;
}

/**
 * @brief  soc set arithmetic Enable
 * @param   enable :enable disable
 * @return  none
 * @note   Note
 */
static void app_soc_arithmeticEnable(bool_t enable)
{
    g_stcSoc.SOC_Enable = enable;
    if(enable)
    {
        g_stcSoc.ChargeWeightFlag = false;
        g_stcSoc.DischargeWeightFlag = false;
        g_stcSoc.SOCRunCount = 0;
		
        if(!g_stcSoc.bdemarcate)
        {
            if(g_stcSoc.PackFullyCharge)
            {
                for(uint8_t i = 0; i < g_stcParm.stcConfig.u8cellS; i++)
                {
                    g_stcSoc.stcdata.i32cellValue[i] = SOC_COEFFICIENT;
                }
                g_stcSoc.PackFullyCharge = false;

                g_stcSoc.stcdata.u8maxChnNum = g_stcVar.u8voltMaxNum - 1;
                g_stcSoc.stcdata.u8minChnNum = g_stcVar.u8voltMinNum - 1;
                g_stcSoc.i32socMax = g_stcSoc.stcdata.i32cellValue[g_stcVar.u8voltMaxNum -1];
                g_stcSoc.i32socMin = g_stcSoc.stcdata.i32cellValue[g_stcVar.u8voltMinNum -1];
            }/* end of if(g_stcSoc.PackFullyCharge) */
            else
            {

            }
        }
        else /* if(!g_stcSoc.bdemarcate) */
        {
            #if 0
            app_soc_cellResetSoc();
            g_stcSoc.bdemarcate = false;
            #endif
        }
        app_soc_weightInitCalc();

        g_stcSoc.stcdata.u32trueValue = g_stcSoc.W1*g_stcSoc.i32socMax + g_stcSoc.W2*g_stcSoc.i32socMin + g_stcSoc.b;

        app_soc_displayWeightCalc();

        if(g_stcSoc.stcdata.u32trueValue >= SOC_COEFFICIENT)
        {
            g_stcSoc.stcdata.u32trueValue = SOC_COEFFICIENT;
            g_stcSoc.stcdata.u32displayValue = SOC_COEFFICIENT;
        }
    }/* end of if(enable) */
    else
    {
        if(g_stcSoc.SOCRunCount != 0)
        {
            g_stcSoc.SOCRunCount = T_SOC_RUN;
            app_soc_arithmetic();
        }
        g_stcSoc.bdemarcate = false; 
    }
}

/**
 * @brief  soc set pack state
 * @param   State :pack state
 * @return  none
 * @note   Note
 */
static void app_soc_setPackState(en_soc_packstate_t State)
{
    g_stcSoc.enSocPackState = State;
    if(State == SOC_PACK_CHARGE_STATE)
    {
        g_stcSoc.ChargeWeightFlag = false;
        app_soc_displayWeightCalc();
    }
    if(State == SOC_PACK_DISCHARGE_STATE)
    {
        g_stcSoc.DischargeWeightFlag = false;
        app_soc_displayWeightCalc();
    }
}

/**
 * @brief  soc arithmetic
 * @param   none
 * @return  none
 * @note   Note
 */
static void app_soc_arithmetic(void)
{
    static uint8_t fullclearflagcnt = 0;
    static uint8_t jumprefreshcnt = 0;
    static uint32_t CacheChargeSocChange = 0;      
    static uint8_t jumpzeroflag = 0;
	
		static uint16_t SocPackEmptyVlue  = 0;

		if (g_stcParm.stcConfig.u8batteryType == TERNARY_MATERIAL_BATTERY_TYPE)
		{
				SocPackEmptyVlue  = SOC_PACKEMPTY_VLUE_NCM;	
		}
		else
		{
				SocPackEmptyVlue  = SOC_PACKEMPTY_VLUE_LFP;	
		}
	
    if(g_stcSoc.bdemarcate == true)
    {
        app_soc_cellResetSoc();
        return;
    }

    if(g_stcSoc.SOC_Enable)
    {
        g_stcSoc.SOCRunCount++;
        if(g_stcSoc.SOCRunCount >= T_SOC_RUN)
        {
            g_stcSoc.SOCRunCount = 0;
            int8_t Temp;
            int32_t Cap;
            int32_t Coulomb;   
            int32_t SOC_Change;   
            //un_afe_balstat_t BalanceState;  
            en_soc_overflowflag_t CellSocFlag = CELL_SOC_NORMAL;

            Temp = app_soc_tempCalc();
            Cap = app_soc_getMaxCapFromTemp(Temp);

            Coulomb = app_soc_coulombCalc();
			
            Coulomb =  Coulomb*(float_t)CAP_COEFFICIENT;
            if((g_stcSoc.enSocPackState == SOC_PACK_CHARGE_STATE)&&(Coulomb > 0))
            {
                SOC_Change = ( COULOMB_EFF_CHARGE * Coulomb) / Cap;            
                {
                    g_stcSoc.u32cycleCapCount += SOC_Change; 
                    if (g_stcSoc.bfullChgCapAutoLearnFlag == true )
                    {                    
                        g_stcSoc.u32fullChgCapCount += SOC_Change; 
                    }
                }
								if ((g_stcSoc.stcdata.u32displayValue >= SOC_COEFFICIENT_ENABLE_JUMP)&&(g_stcSoc.stcdata.u32displayValue <= SOC_COEFFICIENT))
                {
                    if ((g_stcVar.u16voltMax >= g_stcParm.stcConfig.u16fullChgVol)&&(g_stcVar.i32avgCurrent <= g_stcParm.stcConfig.u16fullChgCur))
                    {
                        if (jumprefreshcnt++ >= g_stcParm.stcConfig.u16fullChgDuration)
                        {
														g_stcProtectVar.enfullchgFg = PROTECT_STATE_YES;
														g_stcVar.unProtRank3.bit.full = true; 
                            app_soc_setPackFull(true);
                            jumprefreshcnt = 0;		 
                        } 
                    }
                    else
                    {
                        jumprefreshcnt = 0;
                    }
					
                    if (g_stcSoc.stcdata.u32displayValue >= SOC_COEFFICIENT_DISABLE_REFRESH)
                    {
                        SOC_Change = 0;
                    }
                }
								if(g_stcSoc.stcdata.u32trueValue >= SOC_COEFFICIENT_DISABLE_REFRESH)
								{ 			
                    g_stcSoc.u32chgRemainTime = 60;
								}
								else
								{
                    g_stcSoc.u32chgRemainTime = (float_t)(SOC_COEFFICIENT - g_stcSoc.stcdata.u32trueValue)/SOC_Change;
										if((g_stcSoc.u32chgRemainTime == 0)&&(g_stcSoc.stcdata.u32displayValue < SOC_COEFFICIENT))
										{
												g_stcSoc.u32chgRemainTime = 60;
										}
								}
								g_stcSoc.u32dsgRemainTime = 0;
								jumpzeroflag = 0;
                fullclearflagcnt = 0; 
            }
            else
            { 					
                if ((g_stcVar.i32avgCurrent < 0)&&(g_stcSoc.bfullChgCapAutoLearnFlag == true))
                {
                    if (fullclearflagcnt++ >= 5)
                    {
												if ((g_stcVar.unProtRank1.bit.uv != true)&&(g_stcVar.unProtRank2.bit.uv != true)&&(abs(g_stcVar.i32avgCurrent) >= g_stcParm.stcConfig.u16curThr))
                        {
                            g_stcSoc.bfullChgCapAutoLearnFlag = false;
														g_stcSoc.u32fullChgCapCount = 0;
                        }
												fullclearflagcnt = 0; 
                    }
                }
                else
                {               
                    fullclearflagcnt = 0; 
                }
				
                g_stcSoc.u32cycleCapCount  = 0; 
                SOC_Change = (COULOMB_EFF_DISCHARGE * Coulomb) / Cap; 
								
                SOC_DEBUG("SOC:<< CacheChargeSocChange = %d u32fullChgCapCount = %d u32cycleCapCount = %d  bfullChgCapAutoLearnFlag = %d \r\n",CacheChargeSocChange,g_stcSoc.u32fullChgCapCount,g_stcSoc.u32cycleCapCount,g_stcSoc.bfullChgCapAutoLearnFlag);
                CacheChargeSocChange += abs(SOC_Change); 
                if (CacheChargeSocChange >= SOC_COEFFICIENT)
                {
                    if (g_stcParm.stcConfig.u8soh >= 20)
                    {
                        g_stcParm.stcConfig.u16cycleCount += 1;
                        SOC_DEBUG("SOC:<< ***complete charge write charge cycles*** CacheChargeSocChange = %d \r\n",CacheChargeSocChange);
												g_stcParm.stcConfig.u8soh = (10000 -g_stcParm.stcConfig.u16cycleCount*(SOC_MAX_CYCLE_LOSS/SOC_MAX_CYCLE_NUM))/100;
                        srv_parm_saveCheck();				
                        CacheChargeSocChange -= SOC_COEFFICIENT; 
                    }
										else
                    {          
                        CacheChargeSocChange = 0;
                    }
                }										
								
								if (SOC_Change == 0)
								{
										g_stcSoc.u32dsgRemainTime = 0;
								}
								else
								{
                    g_stcSoc.u32dsgRemainTime = (float_t)(g_stcSoc.stcdata.u32trueValue)/abs(SOC_Change);
								}
                g_stcSoc.u32chgRemainTime = 0;
                jumprefreshcnt = 0;
				
                {
                    if (((g_stcVar.u16voltMin <= SocPackEmptyVlue)&&(g_stcSoc.stcdata.u32displayValue <= SOC_COEFFICIENT_ENABLE_MIN_JUMP))
													||(g_stcVar.unProtRank2.bit.uv == true))
                    {
												g_stcSoc.stcdata.u32trueValue = 0;
												g_stcSoc.stcdata.u32displayValue = 0;
												SOC_Change = 0;
												jumpzeroflag = 1;
                    } 
										else
										{		 
                        jumpzeroflag = 0;
										}
                    if (g_stcSoc.stcdata.u32displayValue <= SOC_COEFFICIENT_DISABLE_MIN_REFRESH)
                    {
                        SOC_Change = 0;
                    }
			
                }	
            }
            SOC_DEBUG("SOC:<< Coulomb=  %d  Cap=  %d  Temp=  %d SOC_Change=  %d \r\n",Coulomb,Cap,Temp,SOC_Change);
            
            for(uint8_t i = 0; i < g_stcParm.stcConfig.u8cellS; i++)
            {
                g_stcSoc.stcdata.i32cellValue[i] += SOC_Change;
            }


            for(uint8_t i = 0; i < g_stcParm.stcConfig.u8cellS; i++)
            {
                //if(g_stcSoc.stcdata.i32cellValue[i] >= SOC_COEFFICIENT ||g_stcSoc.PackFullyCharge)
								if(g_stcSoc.PackFullyCharge == true)
                {
                    g_stcSoc.stcdata.i32cellValue[i] = SOC_COEFFICIENT;  
                    CellSocFlag = CELL_SOC_OVER_TOP;
                }
                else if((g_stcSoc.stcdata.i32cellValue[i] <= 0)||(jumpzeroflag == 1))
                {
                    g_stcSoc.stcdata.i32cellValue[i] = 0;  
                    CellSocFlag = CELL_SOC_TOO_LOW;
                }
                else
                {
                    CellSocFlag = CELL_SOC_NORMAL;
                }
            }

            if(g_stcSoc.PackFullyCharge) 
            {
                g_stcSoc.PackFullyCharge = false;
            }

            g_stcSoc.i32socMax = g_stcSoc.stcdata.i32cellValue[g_stcSoc.stcdata.u8maxChnNum];
            g_stcSoc.i32socMin = g_stcSoc.stcdata.i32cellValue[g_stcSoc.stcdata.u8minChnNum];

            if((CellSocFlag == CELL_SOC_OVER_TOP)&&g_stcSoc.enSocPackState == SOC_PACK_CHARGE_STATE)
            {
                g_stcSoc.stcdata.u32trueValue = SOC_COEFFICIENT;
            }
            else if((CellSocFlag == CELL_SOC_TOO_LOW) && g_stcSoc.enSocPackState == SOC_PACK_DISCHARGE_STATE)
            {
                g_stcSoc.stcdata.u32trueValue = 0;
            }
            else
            {
                uint32_t PackSOC = g_stcSoc.W1*g_stcSoc.i32socMax + g_stcSoc.W2*g_stcSoc.i32socMin + g_stcSoc.b;
                if(PackSOC > SOC_COEFFICIENT)
                {
                    PackSOC = SOC_COEFFICIENT;
                }
                g_stcSoc.stcdata.u32trueValue = PackSOC;
            }
            SOC_DEBUG("SOC:<< W1=  %f  ,   W2=  %f   MAX_VOLTAGE=  %d SOC_Max=  %d MIN_VOLTAGE=  %d SOC_Min=  %d b=  %d\r\n",g_stcSoc.W1,g_stcSoc.W2,g_stcVar.u16voltMax,g_stcSoc.i32socMax ,g_stcVar.u16voltMin,g_stcSoc.i32socMin,g_stcSoc.b);

            if(g_stcParm.stcSoc.u32minLimitSOC >= g_stcSoc.stcdata.u32trueValue)
            {
                g_stcSoc.SOC_Deal = 0;
            }
            else if(g_stcParm.stcSoc.u32maxLimitSOC <= g_stcSoc.stcdata.u32trueValue)
            {
                g_stcSoc.SOC_Deal = SOC_COEFFICIENT;
            }
            else
            {
                g_stcSoc.SOC_Deal = (uint32_t)(((float_t)SOC_COEFFICIENT/
                    (g_stcParm.stcSoc.u32maxLimitSOC - g_stcParm.stcSoc.u32minLimitSOC))*(g_stcSoc.stcdata.u32trueValue - g_stcParm.stcSoc.u32minLimitSOC));
            }
            if(g_stcSoc.SOC_Deal >=SOC_COEFFICIENT)
            {
                g_stcSoc.SOC_Deal = SOC_COEFFICIENT;
            }
            SOC_DEBUG("SOC:<< stcSocReg.W_Display=  %f , stcSocReg.SOC_Deal=  %d  \r\n",g_stcSoc.W_Display,g_stcSoc.SOC_Deal);
            
            if(SOC_PACK_CHARGE_STATE == g_stcSoc.enSocPackState)
            {
                g_stcSoc.stcdata.u32displayValue = g_stcSoc.W_Display*g_stcSoc.SOC_Deal +
                    (float_t)(1 - g_stcSoc.W_Display)*(float_t)SOC_COEFFICIENT;
            }
            else
            {
                g_stcSoc.stcdata.u32displayValue = g_stcSoc.W_Display*g_stcSoc.SOC_Deal;
            }
            if(g_stcSoc.stcdata.u32displayValue > SOC_COEFFICIENT)
            {
                g_stcSoc.stcdata.u32displayValue = SOC_COEFFICIENT;
            }
			
            if((g_stcSoc.enSocPackState == SOC_PACK_DISCHARGE_STATE) &&
                (g_stcSoc.stcdata.u32trueValue < (g_stcSoc.i32socMax - g_stcSoc.i32socMin))
                && !g_stcSoc.DischargeWeightFlag)
            {
                if(g_stcSoc.i32socMin != 0)
                {
                    g_stcSoc.W1 = 0;
                    g_stcSoc.W2 = (float_t)g_stcSoc.stcdata.u32trueValue/(float_t)g_stcSoc.i32socMin;
                    g_stcSoc.b = 0;
                    g_stcSoc.DischargeWeightFlag = true;   
                }
                else   
                {
                    g_stcSoc.W1 = 0;
                    g_stcSoc.W2 = 1;
                    g_stcSoc.b = 0;
                }
            }
            else if((g_stcSoc.enSocPackState == SOC_PACK_CHARGE_STATE) &&
                (g_stcSoc.stcdata.u32trueValue > (SOC_COEFFICIENT - (g_stcSoc.i32socMax - g_stcSoc.i32socMin)))
                 && !g_stcSoc.ChargeWeightFlag)
            {
                if(g_stcSoc.i32socMax != SOC_COEFFICIENT)    
                {
                    g_stcSoc.W1 = ((float_t)(SOC_COEFFICIENT - g_stcSoc.stcdata.u32trueValue)/
                        (float_t)(SOC_COEFFICIENT - g_stcSoc.i32socMax));
                    g_stcSoc.W2 = 0;
                    g_stcSoc.b = (float_t)(1 - g_stcSoc.W1)*(float_t)SOC_COEFFICIENT;
                    g_stcSoc.ChargeWeightFlag = true;     
                }
                else
                {
                    g_stcSoc.W1 = 1;
                    g_stcSoc.W2 = 0;
                    g_stcSoc.b = 0;
                }
            }
            else
            {
                g_stcSoc.W1 = (float_t)(g_stcSoc.i32socMax + g_stcSoc.i32socMin)/(float_t)(2*SOC_COEFFICIENT);
                g_stcSoc.W2 = (float_t)(1 - g_stcSoc.W1);
                g_stcSoc.b = 0;
            }
        }/* end of if(SOC_Reg.SOCRunCount >= T_SOC_RUN) */
    }/* end of if(g_stcSoc.m_stcSocVar.stcSocData.CellValue_Enable) */
}

/**
 * @brief  Temperature capacity initialization
 * @param   none
 * @return  none
 * @note   Note
 */
static void app_soc_capInit(void)
{
    g_stcSoc.u32tempCaTableMaxCap[0] = ((uint32_t)g_stcParm.stcConfig.u32fullChgCap)*7223/1000;
    g_stcSoc.u32tempCaTableMaxCap[1] = ((uint32_t)g_stcParm.stcConfig.u32fullChgCap)*7784/1000;
    g_stcSoc.u32tempCaTableMaxCap[2] = ((uint32_t)g_stcParm.stcConfig.u32fullChgCap)*8679/1000;
    g_stcSoc.u32tempCaTableMaxCap[3] = ((uint32_t)g_stcParm.stcConfig.u32fullChgCap)*9144/1000;
    g_stcSoc.u32tempCaTableMaxCap[4] = ((uint32_t)g_stcParm.stcConfig.u32fullChgCap)*9932/1000;
    g_stcSoc.u32tempCaTableMaxCap[5] = ((uint32_t)g_stcParm.stcConfig.u32fullChgCap)*10000/1000;
    g_stcSoc.u32tempCaTableMaxCap[6] = ((uint32_t)g_stcParm.stcConfig.u32fullChgCap)*10080/1000;
    g_stcSoc.u32tempCaTableMaxCap[7] = ((uint32_t)g_stcParm.stcConfig.u32fullChgCap)*10110/1000;
    g_stcSoc.u32tempCaTableMaxCap[8] = ((uint32_t)g_stcParm.stcConfig.u32fullChgCap)*10120/1000;
    g_stcSoc.u32tempCaTableMaxCap[9] = ((uint32_t)g_stcParm.stcConfig.u32fullChgCap)*10120/1000;	
}

/**
 * @brief  app soc init
 * @param   none
 * @return  none
 * @note   Note
 */
void app_soc_init(void)
{
    memset((void *)&g_stcSoc,0x00,sizeof(stc_soc_t));
	  app_soc_capInit();
	
	  g_stcSoc.bfullChgCapAutoLearnFlag = g_stcParm.stcConfig.u8capAutoLearn;

    g_stcSoc.enSocPackState = SOC_PACK_DISCHARGE_STATE;
    g_stcSoc.PackFullyCharge = false;
    g_stcSoc.SOC_Enable = false;
    g_stcSoc.ChargeWeightFlag = false;
    g_stcSoc.DischargeWeightFlag = false;
}

/**
 * @brief  app soc set pack full
 * @param   enable
 * @return  none
 * @note   Note
 */
void app_soc_setPackFull(bool_t enable)
{
    g_stcSoc.PackFullyCharge = enable;
	
    if (g_stcSoc.bfullChgCapAutoLearnFlag == true )
    {
        if (g_stcSoc.u32fullChgCapCount >(SOC_COEFFICIENT/2))
        {
						SOC_DEBUG("SOC:<< 333333  g_stcParm.stcConfig.u32fullChgCap = %d \r\n",g_stcParm.stcConfig.u32fullChgCap);
            g_stcParm.stcConfig.u32fullChgCap = ((g_stcSoc.u32fullChgCapCount/10000)*(g_stcParm.stcConfig.u32fullChgCap/100));			
            SOC_DEBUG("SOC:<< 111111  g_stcVar.FullChargeCapCount = %d g_stcParm.stcConfig.u32fullChgCap = %d \r\n"
					           ,g_stcSoc.u32fullChgCapCount,g_stcParm.stcConfig.u32fullChgCap);
					
            srv_parm_saveCheck();
            app_soc_capInit();
        }
        //g_stcSoc.enState = SOC_STATE_IDLE;
        g_stcSoc.bfullChgCapAutoLearnFlag = false;
        g_stcSoc.u32fullChgCapCount = 0;
				g_stcSoc.u32chgRemainTime = 0;
    }	
}

/**
 * @brief  app soc task
 * @param   enable
 * @return  none
 * @note   Note
 */
void app_soc_task(void)
{
	#if 1
    static uint8_t waittime = 0;
    switch(g_stcSoc.enState)
    {
        case SOC_STATE_IDLE:
            if (g_stcVar.u32totalSumVolt !=0)
            {
                if (waittime++ >= 2)
                {
                    waittime = 0;
                    g_stcSoc.enState = SOC_STATE_INITWAIT;
                } 			
            }
            break;
        case SOC_STATE_INITWAIT:
            if (true == app_soc_setInitalValue())
            {
                waittime = 0;
                g_stcSoc.enState = SOC_STATE_INIT;
            }
            break;			
        case SOC_STATE_INIT:
            waittime = 0;
            app_soc_arithmeticEnable(true);
            app_soc_setPackState(SOC_PACK_DISCHARGE_STATE);
            g_stcSoc.enState = SOC_STATE_ARITHMETIC;
            break;
        case SOC_STATE_ARITHMETIC:
	        if(g_stcState.enstate == SST_CHG)	
            {
                if(g_stcSoc.enSocPackState != SOC_PACK_CHARGE_STATE)
                {			
                    app_soc_setPackState(SOC_PACK_CHARGE_STATE);
                }
            }
            else if (g_stcState.enstate == SST_DSG)
            {
                if(g_stcSoc.enSocPackState != SOC_PACK_DISCHARGE_STATE)
                {
                    app_soc_setPackState(SOC_PACK_DISCHARGE_STATE);
                }
            }
            else
            {
                app_soc_setPackState(SOC_PACK_DISCHARGE_STATE);
            }	
						
            app_soc_arithmetic();
            break;			
        default:
            waittime = 0;
            break;	
    }
		#endif
}

// =======================================================================================
// End of file.
// =======================================================================================
